
///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2002, Perry L. Miller IV
//  All rights reserved.
//  BSD License: http://www.opensource.org/licenses/bsd-license.html
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//
//  Wrapper class for a single gadget::DigitalInterface.
//
///////////////////////////////////////////////////////////////////////////////

#include "VRV/Devices/ButtonDevice.h"

#include "gadget/Type/Digital.h"

using namespace VRV::Devices;


///////////////////////////////////////////////////////////////////////////////
//
//  Constructor.
//
///////////////////////////////////////////////////////////////////////////////

ButtonDevice::ButtonDevice ( unsigned long mask, const std::string &name ) : 
  BaseClass(),
  _di(),
  _mask ( mask ),
  _pressed(),
  _buttonName ( name )
{
  // Initialize.
  _di.init ( name );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destructor.
//
///////////////////////////////////////////////////////////////////////////////

ButtonDevice::~ButtonDevice()
{
  this->clearButtonPressListeners();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the device mask.
//
///////////////////////////////////////////////////////////////////////////////

unsigned long ButtonDevice::mask () const
{
  Guard guard ( this->mutex() );
  return _mask;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the device state.
//
///////////////////////////////////////////////////////////////////////////////

unsigned long ButtonDevice::state() const
{
  Guard guard ( this->mutex() );

  // Jump through these hoops because getData() is not const.
  DI &di = const_cast < DI & > ( _di );
  return static_cast < unsigned long > ( di->getData() );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Notify listeners if state changed.
//
///////////////////////////////////////////////////////////////////////////////

void ButtonDevice::notify()
{
  Guard guard ( this->mutex() );

  // Get state.
  unsigned long state ( static_cast < unsigned long > ( _di->getData() ) );

  // Notify pressed listeners.
  if ( gadget::Digital::TOGGLE_ON == state )
    this->_notifyPressed();

  // Notify released listeners.
  //if ( gadget::Digital::TOGGLE_OFF == state )
  // this->_notifyReleased();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Notify of button press.
//
///////////////////////////////////////////////////////////////////////////////

void ButtonDevice::_notifyPressed()
{
  ButtonPressListeners pressed;
  {
    Guard guard ( this->mutex() );
    pressed = _pressed;
  }

  std::cout << " Button " << this->getButtonName() << " pressed." << std::endl;

  for ( ButtonPressListeners::iterator iter = pressed.begin(); iter != pressed.end(); ++iter )
  {
    (*iter)();

  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Notify of button release.
//
///////////////////////////////////////////////////////////////////////////////

void ButtonDevice::_notifyReleased()
{
}


///////////////////////////////////////////////////////////////////////////////
//
//  Add the listener.
//
///////////////////////////////////////////////////////////////////////////////

void ButtonDevice::addButtonPressListener ( Callback callback )
{
  // Don't add twice.
  //this->removeButtonPressListener ( callback );

  if ( callback )
  {
    Guard guard ( this->mutex() );
    _pressed.push_back ( callback );
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Remove all render listeners.
//
///////////////////////////////////////////////////////////////////////////////

void ButtonDevice::clearButtonPressListeners()
{
  Guard guard ( this->mutex() );
  _pressed.clear();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the button id.
//
///////////////////////////////////////////////////////////////////////////////

unsigned long ButtonDevice::buttonID () const
{
  Guard guard ( this->mutex () );
  return _mask;
}

///////////////////////////////////////////////////////////////////////////////
//
//  Get the button name
//
///////////////////////////////////////////////////////////////////////////////

std::string ButtonDevice::getButtonName() const
{
  Guard guard ( this->mutex () );
  return _buttonName;
}
